﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TomanuExtensions;
using System.IO;
using System.Diagnostics;
using System.Xml.Linq;
using System.Globalization;
using AmiEmuLib.AmigaConfiguration;
using AmiEmuLib.AmigaConfiguration.ChipsetConfig;
using AmiEmuLib.Host.HostSound;
using AmiEmuLib.Configuration.AmigaAudioConfig;

namespace genblepxml
{
    class AmigaModelData
    {
        public string Name;
        public TVMode TVMode;
        public double C331;
        public double R331;
        public double R332;
        public double R333;
        public double C332;
        public double C333;

        public List<double> BlepLedFilterOff = new List<double>();
        public List<double> BlepLedFilterOn = new List<double>();
        public List<double> BlepUnfiltered = new List<double>();

        public AmigaModelData(string[] a_row, TVMode a_tv_mode)
        {
            Debug.Assert(a_row.Length == 7);

            Name = a_row[0].RemoveFromLeft(1).RemoveFromRight(1);
            TVMode = a_tv_mode;

            C331 = Double.Parse(a_row[1], CultureInfo.InvariantCulture);
            R331 = Double.Parse(a_row[2], CultureInfo.InvariantCulture);
            R332 = Double.Parse(a_row[3], CultureInfo.InvariantCulture);
            R333 = Double.Parse(a_row[4], CultureInfo.InvariantCulture);
            C332 = Double.Parse(a_row[5], CultureInfo.InvariantCulture);
            C333 = Double.Parse(a_row[6], CultureInfo.InvariantCulture);
        }

        public string NameTVMode
        {
            get
            {
                return Name + "-" + TVMode;
            }
        }

        public void ReadBleps(string a_file_name)
        {
            var lines = File.ReadAllLines(a_file_name).ToList();

            var grid = (from line in lines
                        select (from cell in line.Split(",")
                                select cell.Trim()).ToList()).ToList();

            Debug.Assert(grid[0].Count == 3);
            grid.RemoveFirst();

            if (grid.All(row => row.Count == 5))
            {
                foreach (var row in grid)
                {
                    Debug.Assert(row.Last() == "");
                    row.RemoveLast();
                }
            }

            Debug.Assert(grid.All(row => row.Count == 4));
            Debug.Assert(grid.All(row => row.All(s => !String.IsNullOrWhiteSpace(s))));
            Debug.Assert(grid.Count == 2048);

            int index = 0;

            foreach (var line in grid)
            {
                Debug.Assert(Int32.Parse(line[0]) == index);
                index++;

                BlepLedFilterOff.Add(Double.Parse(line[1], CultureInfo.InvariantCulture));
                BlepLedFilterOn.Add(Double.Parse(line[2], CultureInfo.InvariantCulture));
                BlepUnfiltered.Add(Double.Parse(line[3], CultureInfo.InvariantCulture));
            }
        }
    }

    class AmigaModelsData
    {
        public const string AMIGA_MODELS_CSV = @"..\..\..\docs\audio\amiga_filters.csv";
        public const string BLEPS_DIR = @"..\..\..\genblep\";
        public const string BLEPS_MASK = "bleps-unquantized-lsim-*.csv";
        public const string BLEP_BEFORE_MODEL = "bleps-unquantized-lsim-";

        public static AmigaModelData[] Create()
        {
            var lines = File.ReadAllLines(AMIGA_MODELS_CSV).ToList();

            Debug.Assert(lines.Count == 17);

            lines.RemoveAt(10);
            lines.RemoveAt(5);
            lines.RemoveAt(0);

            var grid = (from line in lines
                        select (from cell in line.Split(";")
                                select cell.Trim()).ToArray()).ToArray();

            return (from row in grid
                    select new[] 
                    { 
                        new AmigaModelData(row, TVMode.PAL), 
                        new AmigaModelData(row, TVMode.NTSC) 
                    }).SelectMany().ToArray();
        }
    }

    class GenBlepXml
    {
        static void Main(string[] args)
        {
            var models = AmigaModelsData.Create();

            var files = new DirectoryInfo(AmigaModelsData.BLEPS_DIR).GetFiles(AmigaModelsData.BLEPS_MASK);

            Debug.Assert(files.Length == models.Length);

            var pairs = from file in files
                        select new { file_name = file.FullName, nametvmode = ExtractNameTVMode(file.FullName) };

            foreach (var model in models)
            {
                var file_name = pairs.First(p => p.nametvmode == model.NameTVMode.ToString()).file_name;
                model.ReadBleps(file_name);
            }

            Debug.Assert(models.All(m => !String.IsNullOrWhiteSpace(m.Name)));
            Debug.Assert(models.All(m => m.BlepLedFilterOff.Count != 0));
            Debug.Assert(models.All(m => m.BlepLedFilterOn.Count != 0));
            Debug.Assert(models.All(m => m.BlepUnfiltered.Count != 0));

            var xml = new XElement("AmigaAudioBleps");

            foreach (var model in models)
            {
                xml.Add(CreateBlep(model, model.BlepLedFilterOff, AmigaAudioBlepFilterType.LedOff));
                xml.Add(CreateBlep(model, model.BlepLedFilterOn, AmigaAudioBlepFilterType.LedOn));
                xml.Add(CreateBlep(model, model.BlepUnfiltered, AmigaAudioBlepFilterType.Unfiltered));
            }

            xml.Save(@"..\..\..\amiemu_lib\Configuration\AmigaAudioConfig\AmigaAudioBleps.xml");
        }

        private static XElement CreateBlep(AmigaModelData a_model, List<double> a_list, AmigaAudioBlepFilterType a_filter_type)
        {
            return new XElement("AmigaAudioBlep", 
                new XAttribute("Name", a_model.Name),
                new XAttribute("Model", GetModel(a_model.Name)),
                new XAttribute("TVMode", a_model.TVMode),
                new XAttribute("Filter", a_filter_type),
                new XAttribute("SamplingRate", HostAudioSamplingRate.FQ_44100), 
                BlepLines(a_list));
        }

        private static AmigaModel GetModel(string a_name)
        {
            switch (a_name)
            {

                case "A500 R6a7": return AmigaModel.A500;
                case "A500": return AmigaModel.A500;
                case "A500+": return AmigaModel.A500_Plus;
                case "A600": return AmigaModel.A600;
                case "A1200": return AmigaModel.A1200;
                case "A1200 #2": return AmigaModel.A1200;
                case "A2000 #1": return AmigaModel.A2000;
                case "A2000 #2": return AmigaModel.A2000;
                case "A3000": return AmigaModel.A3000;
                case "CD32": return AmigaModel.CD32;
                case "CDTV": return AmigaModel.CDTV;
                case "A4000": return AmigaModel.A4000;
                case "A500 WinUAE": return AmigaModel.A500;
                case "A1200 WinUAE": return AmigaModel.A1200;
            }

            Debug.Fail("");
            return AmigaModel.Custom;
        }

        private static string BlepLines(List<double> a_list)
        {
            string r = "";
            string NL = Environment.NewLine + "      ";

            for (int i = 0; i < a_list.Count; i++)
            {
                if (i % 5 == 0) 
                    r += NL;

                r = r + a_list[i].ToString(CultureInfo.InvariantCulture) + ", ";

            }

            if (r.EndsWith(NL))
                r = r.RemoveFromRight(NL.Length);

            if (r.EndsWith(", "))
                r = r.RemoveFromRight(2);

            return r;
        }

        private static string ExtractNameTVMode(string a_file_name)
        {
            return Path.GetFileNameWithoutExtension(a_file_name).Replace(AmigaModelsData.BLEP_BEFORE_MODEL, "");
        }
    }
}
